package com.googlecode.textish.format.inline;

import java.io.IOException;
import java.io.Writer;
import java.util.ResourceBundle;

import com.googlecode.textish.format.AbstractFormatter;
import com.googlecode.textish.parser.ContainerTokenDecorator;

/**
 * Base class for inline formatters (think "bold", "italic", etc.). Concerns
 * itself with markers at the beginning and end of words. <strong>This class is
 * not threadsafe.</strong>
 * 
 * @author cgdavies
 * 
 */
public abstract class AbstractInlineFormatter extends AbstractFormatter {

	private String m_marker;

	private String m_prefix;

	private String m_suffix;

	private boolean m_open;

	private boolean m_doClose;

	public AbstractInlineFormatter() {
		// Read the marker, prefix and suffix from the ResourceBundle of the
		// lowest subclass.
		ResourceBundle resourceBundle = ResourceBundle.getBundle(getClass().getName());
		m_marker = resourceBundle.getString("marker");
		m_prefix = resourceBundle.getString("prefix");
		m_suffix = resourceBundle.getString("suffix");

		m_open = false;
		m_doClose = false;
	}

	public boolean afterLine(CharSequence context, ContainerTokenDecorator line, Writer output) throws IOException {
		if (m_open)
			close(output);

		return true;
	}

	public boolean afterParagraph(CharSequence context, ContainerTokenDecorator paragraph, Writer output)
			throws IOException {
		if (m_open)
			close(output);

		return true;
	}

	public boolean afterWord(CharSequence context, ContainerTokenDecorator word, Writer output) throws IOException {
		if (m_doClose) {
			close(output);
			m_doClose = false;
		}

		return true;
	}

	public boolean beforeWord(CharSequence context, ContainerTokenDecorator word, Writer output) throws IOException {
		if (!m_open && context.subSequence(word.getStartIndex(), word.getEndIndex()).toString().startsWith(m_marker)) {
			open(output);
			word.chompStart(m_marker.length());
		}
		else if (m_open
				&& context.subSequence(word.getEndIndex() - m_marker.length(), word.getEndIndex()).equals(m_marker)) {
			// Delay closing until after the word has been written (this gets
			// picked up in the afterWord method).
			m_doClose = true;
			word.chompEnd(m_marker.length());
		}

		return true;
	}

	private void open(Writer output) throws IOException {
		output.append(m_prefix);
		m_open = true;
	}

	private void close(Writer output) throws IOException {
		output.append(m_suffix);
		m_open = false;
	}

}
